﻿using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using HandyControl.Data;
using HandyControl.Tools.Interop;

namespace HandyControl.Tools;

internal class MouseHook
{
    public static event EventHandler<MouseHookEventArgs> StatusChanged;

    private static IntPtr HookId = IntPtr.Zero;

    private static readonly InteropValues.HookProc Proc = HookCallback;

    private static int Count;

    public static void Start()
    {
        if (HookId == IntPtr.Zero)
        {
            HookId = SetHook(Proc);
        }

        if (HookId != IntPtr.Zero)
        {
            Count++;
        }
    }

    public static void Stop()
    {
        Count--;
        if (Count < 1)
        {
            InteropMethods.UnhookWindowsHookEx(HookId);
            HookId = IntPtr.Zero;
        }
    }

    private static IntPtr SetHook(InteropValues.HookProc proc)
    {
        using var curProcess = Process.GetCurrentProcess();
        using var curModule = curProcess.MainModule;

        if (curModule != null)
        {
            return InteropMethods.SetWindowsHookEx((int) InteropValues.HookType.WH_MOUSE_LL, proc,
                InteropMethods.GetModuleHandle(curModule.ModuleName), 0);
        }
        return IntPtr.Zero;
    }

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode < 0) return InteropMethods.CallNextHookEx(HookId, nCode, wParam, lParam);
        var hookStruct = (InteropValues.MOUSEHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(InteropValues.MOUSEHOOKSTRUCT));
        StatusChanged?.Invoke(null, new MouseHookEventArgs
        {
            MessageType = (MouseHookMessageType) wParam,
            Point = new InteropValues.POINT(hookStruct.pt.X, hookStruct.pt.Y)
        });

        return InteropMethods.CallNextHookEx(HookId, nCode, wParam, lParam);
    }
}
